<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Macast</title>

    <script src="/assets/vue@2.6.14.js"></script>
    <script src="/assets/vue-resource@1.5.3.js"></script>
    <script src="/assets/element-ui@2.15.7.js"></script>
    <link rel="shortcut icon" type="image/x-icon" href="/assets/icon.png">
    <link href="https://fonts.font.im/css?family=Noto+Sans" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="/assets/element-ui@2.15.7.css">
</head>
<body>

<div id="app">
    <el-tabs v-model="activeIndex" @tab-click="handleSelect">
        <el-tab-pane label="Plugin" name="1">
            <div class="macast-plugins">
                <macast-plugin v-for="item in plugins" :key="item.renderer"
                               :item="item" v-on:refresh_plugin="refresh_plugin">
                </macast-plugin>
                <p v-if="loading">loading</p>
            </div>
            <a :href="this.repo_url" target="_blank">
                <el-tooltip class="item" effect="dark" content="Find more information at plugins repo."
                            placement="top-end">
                    <el-button class="macast-plugin-repo" icon="el-icon-search" circle>
                    </el-button>
                </el-tooltip>
            </a>
        </el-tab-pane>
        <el-tab-pane label="Setting" name="2">
            <div>
                <el-input
                        type="textarea"
                        :autosize="{ minRows: 2, maxRows: 20}"
                        placeholder="Macast launch parameters"
                        v-model="textarea">
                </el-input>

                <el-tooltip class="item" effect="dark" content="Macast will be restarted" placement="right">
                    <el-button :loading="connecting" :disabled="!is_json" v-on:click="save" round
                               style="margin-top: 10px">Save
                    </el-button>
                </el-tooltip>
                <p v-if="!is_json">json format error</p>
            </div>
        </el-tab-pane>
        <el-tab-pane label="Log" name="3">
            <span>This page does not display all logs. If you want to view all logs, please run from the source code or refer to </span>
            <el-link type="primary"
                     href="https://github.com/xfangfang/Macast/blob/main/.github/ISSUE_TEMPLATE/bug_report.md"
                     target="_blank">this instruction.
            </el-link>
            <br/>
            <br/>
            <span v-html="macast_log"></span>
        </el-tab-pane>
        <el-tab-pane label="Help" name="4">

            <h1>FAQ</h1>

            <el-link type="primary"
                     href="https://github.com/xfangfang/Macast/wiki/FAQ"
                     target="_blank">This document may not be the latest
                version. Please visit the Macast Wiki for the latest document.
            </el-link>

            <p>Macast is still in the early stage of development, so it may not be available on your device. In
                this case, please try the
                <el-link type="primary" href='https://github.com/xfangfang/Macast/actions'>beta version</el-link>
                or
                submit a
                <el-link type="primary" href='https://github.com/xfangfang/Macast/issues/new/choose'>issue</el-link>
                to help us do better.
            </p>
            <h2 id='i-dont-know-how-to-use'>I don&#39;t know how to use</h2>
            <p>Just open this app, and a small icon will appear in the <strong>menubar</strong> /
                <strong>taskbar</strong> / <strong>desktop panel</strong>, then you can push your media files from a
                local DLNA client to your computer.<br/>
            </p>
            <h2 id='how-to-use-third-party-player-plug-inmacast--v06'>How to use third-party player plugin</h2>
            <ol start=''>
                <li>Download the plugin you want from
                    <el-link type="primary" href='https://github.com/xfangfang/Macast-plugins'>
                        xfangfang/Macast-plugins
                    </el-link>
                </li>
                <li>Open the Macast, and click <code>Open Config Directory</code> in the setting menu</li>
                <li>put <strong>[some plugin].py</strong> in renderer directory</li>
                <li>Restart Macast and choose the plugins you want</li>

            </ol>
            <p> if you can&#39;t find any plugin you want, check
                <el-link type="primary"
                         href='https://github.com/xfangfang/Macast/wiki/Custom-Renderer'>here
                </el-link>
                to learn how to write a
                custom renderer plug-in, and feel welcome to open a pull requests.
            </p>
            <h2 id='unable-to-find-macast-from-your-dlna-client'>Unable to find Macast from your DLNA client</h2>
            <ul>
                <li>Check whether your firewall blocks Macast. <br/>A simple way to check firewall is to access the port
                    opened by Macast from other devices (the default is 1068, and you can find in the settings menu)
                </li>
                <li>Check your router.<br/>You should open UPnP and close AP Isolation.</li>
                <li>Software problems.<br/>If you are using an iOS device, please make sure that the app&#39;s
                    permission to <strong>find and connect to devices on your local network</strong> is turned on. <br/>And
                    on some application, you need to wait more than 30s to find Macast. Please wait patiently.
                </li>
                <li>UDP multicast problem.<br/>It is said that Windows and some routers will have adaptation problems,
                    resulting in the failure of Windows to join multicast. In this case, You need to modify the windows
                    registry to force IGMP version to v2.
                </li>
                <li>Multiple network cards or complex network conditions. <br/>Ensure that Macast can be used under the
                    condition of single network card and the same LAN with your DLNA client, solutions for more complex
                    situations are still working in progress.
                </li>

            </ul>
            <h2 id='crash-at-startup'>Crash at startup</h2>
            <p> Macast opens port 1068 by default. When there is a port conflict on your computer, the application will
                crash. Please set the application port manually.
                , then Macast will load the ports you specify from the configuration file.</p>
            <h2 id='unable-to-close-or-unresponsive'>Unable to close or unresponsive</h2>
            <p> When a third-party player plug-in is used, the plug-in usually needs to open more threads or processes,
                resulting in a non response problem when the application exits, which is usually caused by the plug-in
                itself.</p>
            <h2 id='where-is-the-configuration-file-located'>where is the configuration file located</h2>
            <figure>
                <table>
                    <thead>
                    <tr>
                        <th>platform</th>
                        <th>path</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr>
                        <td>MacOS</td>
                        <td><code>$HOME/Library/Application\ Support/Macast/</code></td>
                    </tr>
                    <tr>
                        <td>Linux</td>
                        <td><code>$HOME/.config/Macast</code></td>
                    </tr>
                    <tr>
                        <td>Windows</td>
                        <td><code>%HOMEPATH%\AppData\Local\xfangfang\Macast</code></td>
                    </tr>
                    </tbody>
                </table>
            </figure>
            <h2 id='language-support'>Language support</h2>
            <p>check the shell command in
                <el-link type="primary" href='https://github.com/xfangfang/Macast/blob/main/docs/i18n.md'>docs/i18n.md
                </el-link>
                ,
                feel free to open a pull requests.
            </p>
            <h2 id='how-to-set-personal-configurations-to-mpv'>How to set personal configurations to mpv</h2>
            <p> refer to the mpv manual about how to set personal configs:
                <el-link type="primary" href='https://mpv.io/manual/stable/#files'
                         target='_blank' class='url'>https://mpv.io/manual/stable/#files
                </el-link>
            </p>
            <p> create a configuration file at :</p>
            <figure>
                <table>
                    <thead>
                    <tr>
                        <th>platform</th>
                        <th>path</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr>
                        <td>MacOS</td>
                        <td><code>~/.config/mpv/mpv.conf</code></td>
                    </tr>
                    <tr>
                        <td>Linux</td>
                        <td><code>~/.config/mpv/mpv.conf</code></td>
                    </tr>
                    <tr>
                        <td>Windows</td>
                        <td><code>%HOMEPATH%\AppData\Roaming\mpv\mpv.conf</code></td>
                    </tr>
                    </tbody>
                </table>
            </figure>
            <p> and put some mpv command line options into the <strong>configuration file</strong>, like:</p>
            <pre><code>fs-screen==1
</code></pre>
            <p><em>this option tells mpv to fullscreen open a new video in desktop 1. more about fs-screen options:
                <el-link type="primary"
                         href='https://mpv.io/manual/stable/#options-fs-screen' target='_blank' class='url'>
                    https://mpv.io/manual/stable/#options-fs-screen
                </el-link>
            </em>
            </p>
            <p> In this way, you can also modify the shortcut keys of the mpv player -- just put
                <strong>input.conf</strong> to the same directory:
                <el-link type="primary" href='https://mpv.io/manual/stable/#input-conf'
                         target='_blank' class='url'>https://mpv.io/manual/stable/#input-conf
                </el-link>
            </p>
        </el-tab-pane>
    </el-tabs>

</div>
<div class='footer'></div>

<script type="text/x-template" id="plugin">
    <el-card class="box-card" shadow="hover">
        <div slot="header" class="clearfix">
            <span class="macast-plugin-name">{{ item.title }} </span>
            <br/>
            <div class="macast-plugin-header">
                <span>{{ item.platform }}</span>
                <el-tag size="small" :type="item.version_tag_type" effect="plain">{{ item.version_tag }}</el-tag>
            </div>
        </div>
        <div class="macast-plugin-content">{{ item.desc }}</div>

        <div class="macast-plugin-footer">
            <div class="macast-plugin-avatar">
                <el-avatar size="small" :src="circleUrl"></el-avatar>
                <span class="macast-plugin-author">{{ item.author ? item.author : "Macast"  }}</span>
            </div>
            <el-tooltip class="item" effect="dark" :content="item.hint" placement="top">
                <el-button
                        :disabled="!item.available"
                        class="macast-plugin-install"
                        v-if="item.need_update"
                        :type="item.version_tag_type"
                        round
                        v-on:click="install">
                    {{item.button_text}}
                </el-button>
            </el-tooltip>

        </div>
    </el-card>
</script>

<script type="text/javascript">
    const NotFound = {template: '<p>Page not found</p>'}
    Vue.component('macast-plugin', {
        template: '#plugin',
        props: ['item', 'update'],
        data() {
            return {
                circleUrl: '/assets/avatar.png',
                loading: false
            }
        },
        async mounted() {
            this.get_github_avatar()
        },
        methods: {
            async get_github_avatar() {
                if (!this.item.author) {
                    this.circleUrl = "/assets/icon.ico"
                    return;
                }

                let url = `https://api.github.com/users/${this.item.author}`
                this.$http.get(url).then(res => {
                    this.circleUrl = res.data.avatar_url;
                }).catch(err => {
                    console.log(err)
                })
            },
            async install(evt) {
                this.loading = true;
                this.$emit('refresh_plugin',
                    {type: this.item.type, url: this.item.url}
                )
            },
        }
    })
    new Vue({
        el: '#app',
        data: {
            currentRoute: window.location.pathname,
            backend_url: '/api',
            activeIndex: '1',

            //plugin
            loading: true,
            repo_plugins: [],
            local_plugins: [],
            plugins: [],
            repo_url: '',
            platform: '',
            macast_version: 0,
            refresh_interval_id: 0,


            //setting
            textarea: '',
            interval_id: 0,
            connecting: false,

            DLNA_FriendlyName: "",

            //log
            macast_log: ''

        },
        mounted() {
            window.addEventListener('popstate', res => {
                if (res.state) {
                    this.activeIndex = res.state.page;
                } else {
                    this.activeIndex = '1';
                }
            });
            let page = this.getQueryString('page');
            console.log(page);
            this.switch_page(page);
            this.load_local_plugin();
            this.load_repo_plugin();
            this.get_log();
        },
        activated() {

        },
        computed: {
            is_json() {
                try {
                    let obj = JSON.parse(this.textarea);
                    return !!(typeof obj == 'object' && obj);
                } catch (e) {
                    return false;
                }
            },
        },
        methods: {
            getQueryString(name) {
                let reg = `(^|&)${name}=([^&]*)(&|$)`
                let r = window.location.search.substr(1).match(reg);
                if (r != null) return unescape(r[2]);
                return null;
            },
            async get_log() {
                let url = '/api?query=log';
                this.$http.get(url).then(res => {
                    let logs = res.data.logs.replace(new RegExp("\n", "gm"), '<br/>')
                    this.macast_log = logs;
                }).catch(err => {
                    this.$message.error('Error connecting to Macast');
                });
            },
            async handleSelect(tab, event) {
                this.switch_page(tab.name)
            },
            async switch_page(page_name) {
                console.log('switch page:', page_name)
                switch (page_name) {
                    case '1':
                        this.load_local_plugin();
                        this.load_repo_plugin();
                        this.set_history(page_name);
                        break;
                    case '2':
                        this.connecting = true;
                        let res = await this.get_settings()
                        this.connecting = false
                        this.set_history(page_name);
                        break;
                    case '3':
                        this.set_history(page_name);
                        this.get_log();
                        break;
                    case '4':
                        this.set_history(page_name);
                        break;
                }
            },
            async set_history(page_name) {
                this.activeIndex = page_name;
                if (!!(window.history && history.pushState)) {
                    history.pushState({page: page_name}, 'Macast', `?page=${page_name}`)
                }
            },
            async load_repo_plugin() {
                console.log('update plugin info')
                let url = 'https://raw.githubusercontent.com/xfangfang/Macast-plugins/main/info.json'
                return this.$http.get(url).then(res => {
                    this.repo_url = res.data.repo_url
                    this.repo_plugins = res.data.plugin_v1
                    this.update_plugins();
                    this.loading = false
                    return true;
                }).catch(err => {
                    console.log(err);
                    this.$message.error('Error connecting to plugin repo.');
                    return false;
                })
            },
            async load_local_plugin() {
                let url = '/api?query=plugin-info'
                return this.$http.get(url).then(res => {
                    console.log(res.data)
                    this.macast_version = res.data.macast_version;
                    this.platform = res.data.platform;
                    this.local_plugins = res.data.plugins;
                    this.plugins = []
                    this.$nextTick(() => {
                        this.update_plugins();
                    })
                    return true;
                }).catch(err => {
                    console.log(err)
                    this.$message.error('Error connecting to Macast');
                    return false;
                })
            },
            async get_settings() {
                let url = '/api?query=launch-param'
                return this.$http.get(url).then(res => {
                    return res.text()
                }).then(res => {
                    console.log(res)
                    res = res.replace(new RegExp("\\\\u", "gm"), '%u')
                    this.textarea = unescape(res)
                    return true;
                }).catch(err => {
                    console.log(err)
                    this.$message.error('Error connecting to Macast');
                    return false;
                })
            },
            save() {
                console.log(this.textarea)
                let url = '/api'
                let uploadData = new window.FormData()
                uploadData.append('save-launch-param', this.textarea)
                this.$http.post(url, uploadData).then(res => {
                    console.log(res)
                }).catch(err => {
                    console.log(err)
                    this.$message.error('Error connecting to Macast');
                })
                this.connecting = true;
                this.interval_id = setInterval(
                    async () => {
                        let res = await this.get_settings()
                        console.log('get_settings:', res)
                        if (res) {
                            clearInterval(this.interval_id)
                            this.connecting = false;
                            this.$notify({
                                title: 'Success',
                                message: 'Macast restart',
                                duration: 0
                            });
                        }
                    }, 1000)
            },
            isMobile() {
                let flag = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)
                return flag;
            },
            async refresh_plugin(data) {
                console.log(data)
                let uploadData = new window.FormData()
                uploadData.append('install-plugin', JSON.stringify(data))
                const loading = this.$loading({
                    lock: true,
                    text: 'Installing',
                    spinner: 'el-icon-loading',
                    background: 'rgba(0, 0, 0, 0.7)'
                });
                await this.$http.post('/api', uploadData).then(res => {
                    console.log(res.data)
                    if (res.data.code !== 0) {
                        console.log(res.data.message)
                        this.$message.error(res.data.message);
                        loading.close();
                        return
                    }
                    this.refresh_interval_id = setInterval(
                        async () => {
                            let res = await this.load_local_plugin()
                            console.log('load_local_plugin:', res)
                            if (res) {
                                clearInterval(this.refresh_interval_id)
                                loading.close();
                            }
                        }, 1000)
                }).catch(err => {
                    console.log(err)
                    this.$message.error('Error connecting to Macast');
                    loading.close();
                })
            },
            update_plugins() {
                this.plugins = [];
                for (let p of this.local_plugins) {
                    let data = {
                        title: p.title,
                        platform: p.platform, //插件适配的操作系统
                        available: p.platform.indexOf(this.platform) !== -1, // 是否适配当前系统
                        local_version: parseFloat(p.version), // 本地版本号
                        repo_version: 0, // 线上版本号
                        version_tag: `v${p.version}`,
                        version_tag_type: 'success',
                        author: p.author,
                        desc: p.desc,
                        type: p.type, //插件类型：protocol / renderer
                        renderer: p.renderer,
                        protocol: p.protocol,
                        need_update: false, // 是否需要更新
                        plugin_type: p.default ? 'default' : 'local', // 插件类型：默认插件、本地插件（有无更新）、在线插件（是否适配当前系统）
                        hint: 'Macast will be restarted',
                        button_text: 'Update',
                        url: ''
                    }
                    this.plugins.push(data)
                }
                for (let p of this.repo_plugins) {
                    let have_local = false
                    for (let l of this.plugins) {
                        if ((l.renderer === p.renderer && l.type === 'renderer') ||
                            l.protocol === p.protocol && l.type === 'protocol') {
                            // 本地插件拥有对应的在线插件
                            have_local = true
                            l['repo_version'] = parseFloat(p.version)
                            l['desc'] = p.desc
                            l['need_update'] = l.local_version < l.repo_version
                            l['url'] = p.url
                            if (l['need_update']) {
                                l['version_tag'] += ` => ${p.version}`
                                l['version_tag_type'] = 'warning'
                            } else if (l.local_version !== l.repo_version) {
                                l['version_tag'] = `v${l.local_version} / v${l.repo_version}`
                            }
                        }
                    }
                    if (!have_local) {
                        // 没有对应的本地插件
                        let data = {
                            title: p.title,
                            platform: p.platform, //插件适配的操作系统
                            available: p.platform.indexOf(this.platform) !== -1, // 是否适配当前系统
                            local_version: 0, // 本地版本号
                            repo_version: parseFloat(p.version), // 线上版本号
                            version_tag: `v${p.version}`,
                            version_tag_type: '',
                            author: p.author,
                            desc: p.desc,
                            type: p.type, //插件类型：protocol / renderer
                            renderer: p.renderer,
                            protocol: p.protocol,
                            need_update: true,
                            plugin_type: 'repo',
                            hint: 'Macast will be restarted',
                            button_text: 'Install',
                            url: p.url
                        }
                        this.plugins.push(data)
                    }
                }
            }
        }
    })
</script>

<style lang="scss">

    body {
        margin: 20px;
        font-family: 'Noto Sans', sans-serif;
    }

    header {
        float: none !important;
    }

    /*plugin style*/
    .macast-plugins {
        display: flex;
        flex-wrap: wrap;
    }

    .macast-plugin-name {
        font-weight: bolder;
        font-size: x-large;
    }

    .macast-plugin-content {
        margin: 10px;
        height: 100px;
    }

    .macast-plugin-avatar {
        display: flex;
        align-items: center;
        margin: 10px;
    }

    .macast-plugin-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-top: 10px;
    }

    .macast-plugin-footer {
        display: flex;
        justify-content: space-between;
    }

    .macast-plugin-install {
        margin: 10px;
        margin-right: 16px;
    }

    .macast-plugin-author {
        margin-left: 8px;
    }

    .macast-plugin-repo {
        width: 3rem;
        height: 3rem;
        position: fixed;
        bottom: 1rem;
        right: 1rem;
        z-index: 9999;
    }

    .item {
        margin-bottom: 18px;
    }

    .clearfix:before,
    .clearfix:after {
        display: table;
        content: "";
    }

    .clearfix:after {
        clear: both
    }

    .box-card {
        width: 320px;
        margin: 10px;
    }

    /*plugin style end*/


</style>

</body>
</html>